React Suspense ๋ฆฌ์†Œ์Šค ์กฐ์ •: ๋‹ค์ค‘ ๋ฆฌ์†Œ์Šค ๋กœ๋”ฉ ๊ด€๋ฆฌ ๋งˆ์Šคํ„ฐํ•˜๊ธฐ | MLOG | MLOG

์žฅ์ :

๋‹จ์ :

2. ์ข…์†์„ฑ์„ ์‚ฌ์šฉํ•œ ์ˆœ์ฐจ ๋กœ๋”ฉ

๋ฆฌ์†Œ์Šค๊ฐ€ ์„œ๋กœ ์˜์กดํ•˜๋Š” ๊ฒฝ์šฐ ์ˆœ์ฐจ์ ์œผ๋กœ ๋กœ๋“œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. Suspense๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ข…์† ๋ฆฌ์†Œ์Šค๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ค‘์ฒฉํ•˜์—ฌ ์ด๋Ÿฌํ•œ ํ๋ฆ„์„ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ์‹œ: ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ๋ฅผ ๋จผ์ € ๋กœ๋“œํ•œ ๋‹ค์Œ ์‚ฌ์šฉ์ž ID๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒŒ์‹œ๋ฌผ์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

            
import React, { Suspense } from 'react';
import fetchData from './fetchData';

const userResource = fetchData('/api/user');

function UserPosts({ userId }) {
  const postsResource = fetchData(`/api/posts?userId=${userId}`);
  const posts = postsResource.read();

  return (
    
    {posts.map((post) => (
  • {post.title}
  • ))}
); } function UserProfile() { const user = userResource.read(); return (

{user.name}

{user.bio}

Posts

Loading posts...
}>
); } function App() { return ( Loading user profile...}> ); } export default App;

์žฅ์ :

๋‹จ์ :

3. ๋ณ‘๋ ฌ ๋ฐ ์ˆœ์ฐจ ๋กœ๋”ฉ ๊ฒฐํ•ฉ

๋งŽ์€ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•˜๊ธฐ ์œ„ํ•ด ๋ณ‘๋ ฌ ๋ฐ ์ˆœ์ฐจ ๋กœ๋”ฉ์„ ๋ชจ๋‘ ๊ฒฐํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋…๋ฆฝ์ ์ธ ๋ฆฌ์†Œ์Šค๋ฅผ ๋ณ‘๋ ฌ๋กœ ๋กœ๋“œํ•œ ๋‹ค์Œ ๋…๋ฆฝ์ ์ธ ๋ฆฌ์†Œ์Šค๊ฐ€ ๋กœ๋“œ๋œ ํ›„ ์ข…์† ๋ฆฌ์†Œ์Šค๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์‹œ: ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ์™€ ์ตœ๊ทผ ํ™œ๋™์„ ๋ณ‘๋ ฌ๋กœ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ๊ฐ€ ๋กœ๋“œ๋œ ํ›„ ์‚ฌ์šฉ์ž์˜ ๊ฒŒ์‹œ๋ฌผ์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

            
import React, { Suspense } from 'react';
import fetchData from './fetchData';

const userResource = fetchData('/api/user');
const activityResource = fetchData('/api/activity');

function UserPosts({ userId }) {
  const postsResource = fetchData(`/api/posts?userId=${userId}`);
  const posts = postsResource.read();

  return (
    
    {posts.map((post) => (
  • {post.title}
  • ))}
); } function UserProfile() { const user = userResource.read(); const activity = activityResource.read(); return (

{user.name}

{user.bio}

Last activity: {activity.date}

Posts

Loading posts...
}>
); } function App() { return ( Loading user profile...}> ); } export default App;

์ด ์˜ˆ์‹œ์—์„œ๋Š” `userResource`์™€ `activityResource`๊ฐ€ ๋ณ‘๋ ฌ๋กœ ๊ฐ€์ ธ์™€์ง‘๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ๊ฐ€ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ด์ง€๋ฉด `UserPosts` ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง๋˜์–ด ์‚ฌ์šฉ์ž ๊ฒŒ์‹œ๋ฌผ์— ๋Œ€ํ•œ ๊ฐ€์ ธ์˜ค๊ธฐ๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.

์žฅ์ :

๋‹จ์ :

4. ๋ฆฌ์†Œ์Šค ๊ณต์œ ๋ฅผ ์œ„ํ•œ React Context ์‚ฌ์šฉ

React Context๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ ๊ฐ„์— ๋ฆฌ์†Œ์Šค๋ฅผ ๊ณต์œ ํ•˜๊ณ  ๋™์ผํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ๋‹ค์‹œ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋™์ผํ•œ ๋ฆฌ์†Œ์Šค์— ์•ก์„ธ์Šคํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ํŠนํžˆ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์‹œ:

            
import React, { createContext, useContext, Suspense } from 'react';
import fetchData from './fetchData';

const UserContext = createContext(null);

function UserProvider({ children }) {
  const userResource = fetchData('/api/user');

  return (
    
      {children}
    
  );
}

function UserProfile() {
  const userResource = useContext(UserContext);
  const user = userResource.read();

  return (
    

{user.name}

{user.bio}

); } function UserAvatar() { const userResource = useContext(UserContext); const user = userResource.read(); return ( {user.name} ); } function App() { return ( Loading user profile...
}> ); } export default App;

์ด ์˜ˆ์‹œ์—์„œ `UserProvider`๋Š” ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€ `UserContext`๋ฅผ ํ†ตํ•ด ๋ชจ๋“  ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์— ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. `UserProfile` ๋ฐ `UserAvatar` ์ปดํฌ๋„ŒํŠธ ๋ชจ๋‘ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์‹œ ๊ฐ€์ ธ์˜ค์ง€ ์•Š๊ณ  ๋™์ผํ•œ ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์žฅ์ :

๋‹จ์ :

5. ๊ฐ•๋ ฅํ•œ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ์˜ค๋ฅ˜ ๊ฒฝ๊ณ„

Suspense๋Š” ์˜ค๋ฅ˜ ๊ฒฝ๊ณ„์™€ ํ•จ๊ป˜ ์ž‘๋™ํ•˜์—ฌ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ ๋˜๋Š” ๋ Œ๋”๋ง ์ค‘์— ๋ฐœ์ƒํ•˜๋Š” ์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์˜ค๋ฅ˜ ๊ฒฝ๊ณ„๋Š” ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ์—์„œ JavaScript ์˜ค๋ฅ˜๋ฅผ ์žก๊ณ , ํ•ด๋‹น ์˜ค๋ฅ˜๋ฅผ ๊ธฐ๋กํ•˜๊ณ , ์ „์ฒด ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ๊ฐ€ ์ถฉ๋Œํ•˜๋Š” ๋Œ€์‹  ๋Œ€์ฒด UI๋ฅผ ํ‘œ์‹œํ•˜๋Š” React ์ปดํฌ๋„ŒํŠธ์ž…๋‹ˆ๋‹ค.

์˜ˆ์‹œ:

            
import React, { Suspense } from 'react';
import fetchData from './fetchData';
import ErrorBoundary from './ErrorBoundary';

const userResource = fetchData('/api/user');

function UserProfile() {
  const user = userResource.read();

  return (
    

{user.name}

{user.bio}

); } function App() { return ( Something went wrong!
}> Loading user profile...}> ); } export default App;

์ด ์˜ˆ์‹œ์—์„œ `ErrorBoundary`๋Š” `UserProfile` ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜๊ฑฐ๋‚˜ ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋™์•ˆ ๋ฐœ์ƒํ•˜๋Š” ๋ชจ๋“  ์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋Œ€์ฒด UI๋ฅผ ํ‘œ์‹œํ•˜์—ฌ ์ „์ฒด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ถฉ๋Œํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.

์žฅ์ :

๋‹จ์ :

๊ธ€๋กœ๋ฒŒ ์ž ์žฌ ๊ณ ๊ฐ์„ ์œ„ํ•œ ์‹ค์งˆ์ ์ธ ๊ณ ๋ ค ์‚ฌํ•ญ

๊ธ€๋กœ๋ฒŒ ์ž ์žฌ ๊ณ ๊ฐ์„ ์œ„ํ•œ React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•  ๋•Œ๋Š” ๋‹ค์Œ์„ ๊ณ ๋ คํ•˜์‹ญ์‹œ์˜ค:

์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ์ธ์‚ฌ์ดํŠธ ๋ฐ ๋ชจ๋ฒ” ์‚ฌ๋ก€

React Suspense๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์ค‘ ๋ฆฌ์†Œ์Šค ๋กœ๋”ฉ์„ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๋ช‡ ๊ฐ€์ง€ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ์ธ์‚ฌ์ดํŠธ์™€ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

๊ฒฐ๋ก 

React Suspense๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์„ ๊ด€๋ฆฌํ•˜๊ณ  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ๊ฐœ์„ ํ•˜๋Š” ๊ฐ•๋ ฅํ•˜๊ณ  ์œ ์—ฐํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. Suspense์™€ ๋ฆฌ์†Œ์Šค์˜ ํ•ต์‹ฌ ๊ฐœ๋…์„ ์ดํ•ดํ•˜๊ณ  ์ด ๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๋ฌผ์— ์„ค๋ช…๋œ ์ „๋žต์„ ์ ์šฉํ•จ์œผ๋กœ์จ ๋‹ค์ค‘ ๋ฆฌ์†Œ์Šค ๋กœ๋”ฉ์„ ํšจ๊ณผ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ณ  ๊ธ€๋กœ๋ฒŒ ์ž ์žฌ ๊ณ ๊ฐ์„ ์œ„ํ•ด ๋” ๋ฐ˜์‘์ ์ด๊ณ  ๊ฒฌ๊ณ ํ•œ React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ „ ์„ธ๊ณ„ ์‚ฌ์šฉ์ž๋ฅผ ์œ„ํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•  ๋•Œ๋Š” ๊ตญ์ œํ™”, ์ ‘๊ทผ์„ฑ ๋ฐ ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ๊ณ ๋ คํ•˜๋Š” ๊ฒƒ์„ ์žŠ์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ์ด๋Ÿฌํ•œ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ๋”ฐ๋ฅด๋ฉด ๊ธฐ๋Šฅ์ ์ผ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋ชจ๋“  ์‚ฌ๋žŒ์—๊ฒŒ ์‚ฌ์šฉ์ž ์นœํ™”์ ์ด๊ณ  ์•ก์„ธ์Šค ๊ฐ€๋Šฅํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.